package cn.seaboot.admin.mvc.response;

import cn.seaboot.admin.mvc.Problem;
import cn.seaboot.admin.mvc.Result;
import cn.seaboot.commons.exception.BizException;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.annotation.Annotation;

/**
 * 全局返回值处理
 * <p>
 * Controller 返回数据格式化设置，此域名下的全部 Controller 有效
 *
 * @author Created by Mr.css on 2018-05-11.
 * @version 2018-05-11.
 */
//@ControllerAdvice
//@ControllerAdvice(basePackages = "cn.seaboot")
public class ControllerReturnValueAdvice implements ResponseBodyAdvice<Object> {

    /**
     * 为了提高代码效率，可以直接返回 true。
     * <p>
     * 这意味着，如果在 controller 中写业务代码，可能会受到影响；
     * 比如：模版引擎渲染的界面，会受到影响。
     *
     * @param params the return type
     * @param clazz  the selected converter type
     * @return {@code true} if {@link #beforeBodyWrite} should be invoked;
     * {@code false} otherwise
     */
    @Override
    public boolean supports(@NotNull MethodParameter params,
                            @NotNull Class<? extends HttpMessageConverter<?>> clazz) {
        return params.hasMethodAnnotation(ResponseBody.class);
    }

    /**
     * 标准模式（兼容 restful）
     * <p>
     * 正常情况下，应当采用这种方式进行处理。
     *
     * @param param the return type
     * @param clazz the selected converter type
     * @return {@code true} if {@link #beforeBodyWrite} should be invoked;
     * {@code false} otherwise
     */
    public boolean strictSupports(@NotNull MethodParameter param,
                                  @NotNull Class<? extends HttpMessageConverter<?>> clazz) {
        Annotation[] annotations = param.getMethodAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof ResponseBody) {
                return true;
            } else {
                // restful 兼容
                RequestMapping requestMapping = annotation.annotationType().getAnnotation(RequestMapping.class);
                if (requestMapping != null) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public Object beforeBodyWrite(Object o
            , @NotNull MethodParameter methodParameter
            , @NotNull MediaType mediaType
            , @NotNull Class<? extends HttpMessageConverter<?>> aClass
            , @NotNull ServerHttpRequest request
            , @NotNull ServerHttpResponse response) {
        if (o instanceof Integer) {
            Integer i = (Integer) o;
            if(i > 0){
                // succeed
                return Result.succeed();
            } else {
                // not modified
                response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                return Result.NOT_MODIFIED;
            }
        } else if (o instanceof Problem) {
            // 返回 Problem，则返回 problem+json
            HttpStatus status = ((Problem) o).getStatus();
            if (status == null) {
                status = HttpStatus.INTERNAL_SERVER_ERROR;
            }
            response.setStatusCode(status);
            response.getHeaders().setContentType(MediaType.APPLICATION_PROBLEM_JSON);
            return o;
        } else {
            return o;
        }
    }

    /**
     * 无效的修改
     * <p>
     * 操作成功，但是数据修改后与之前完全一致
     *
     * @param response -
     * @return -
     */
    public Object noEffect(@NotNull ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        response.getHeaders().setContentType(MediaType.APPLICATION_PROBLEM_JSON);
        return Problem.builder().withStatus(HttpStatus.INTERNAL_SERVER_ERROR).withTitle("无效的操作！").build();
    }

    /**
     * 将 Result 转为 problem+json
     *
     * @param result   -
     * @param request  -
     * @param response -
     * @return -
     */
    private Object withResul(Result result, @NotNull ServerHttpRequest request
            , @NotNull ServerHttpResponse response) {
        if (result.getCode() == 0) {
            return result.getData();
        } else {
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            response.getHeaders().setContentType(MediaType.APPLICATION_PROBLEM_JSON);
            return Problem.builder().withStatus(HttpStatus.INTERNAL_SERVER_ERROR).withTitle((String) result.getData()).build();
        }
    }
}
